//
// Created by 13281 on 2023/3/14.
//

#include <iostream>
#include "SCComponent.h"

SCComponent::SCComponent() {}

void SCComponent::addNode(int node) {
    nodes.push_back(node);
}

void SCComponent::addEdge(Word word) {
    int head = word.getHeadLetter() - 'a';
    int tail = word.getTailLetter() - 'a';
    linkList[head].push_back(word);
    linkMap[head][tail].push_back(word);
    if (longest_link[head][tail] == nullptr
        || word.getLength() > longest_link[head][tail]->getLength()) {
        longest_link[head][tail] = &word;
    }
}


vector<int> SCComponent::getNodes() {
    return nodes;
}

void SCComponent::searchPaths() {
    auto *visited = new set<string>();
    for (int node : nodes) {
        searchPathsFrom(node, new WordChain(), visited);
    }
//    cout << "___________________" << endl;
//    for (int i : nodes) {
//        cout << (char)('a' + i) << " ";
//    }
//    cout << endl;
//    for (int i : nodes) {
//        for (int j : nodes) {
//            if (sccLongestPath[i][j] != nullptr) {
//                cout << sccLongestPath[i][j]->toString() << " " << endl;
//            }
//        }
//    }
//    for (int i = 0; i < 26; i++) {
//        for (int j = 0; j < 26; j++) {
//            if (sccLongestPath[i][j] != nullptr) {
//                cout << (char)('a' + i) << " " << (char)('a' + j)  << "~~~~" << sccLongestPath[i][j]->toString() << endl;
//                WordChain chain = getLongestPathBetween(i, j);
//                cout << chain.toString() << endl;
//            }
//        }
//    }
//    WordChain chain = getLongestPathBetween('w' - 'a', 'd' - 'a');
//    cout << "@@@" << chain.toString() <<endl;
    delete visited;
}

void SCComponent::searchPathsFrom(int node, WordChain *prevChain, set<string> *passed) {
    if (prevChain->getWordNum() > 0) {
        int head = prevChain->getHead() - 'a';
        int tail = prevChain->getTail() - 'a';
//        cout << "add " << prevChain->toString() << endl;
        paths[head][tail].push_back(*prevChain);
        if (sccMostPath[head][tail] == nullptr
            || prevChain->getWordNum() > sccMostPath[head][tail]->getWordNum()) {
            sccMostPath[head][tail] = prevChain;
//            cout << "!" << "Path between " << (char)('a' + head) << " " << (char)('a' + tail) << ": " << sccMostPath[head][tail]->toString() << endl;;
        }
        if (sccLongestPath[head][tail] == nullptr
            || prevChain->getLetterNum() > sccLongestPath[head][tail]->getLetterNum()) {
            sccLongestPath[head][tail] = prevChain;
//            cout << "?" << "Path between " << (char)('a' + head) << " " << (char)('a' + tail) << ": " << sccLongestPath[head][tail]->toString() << endl;
        }
    }
    for (Word word : linkList[node]) {
        if (passed->count(word.str)) {
            continue;
        }
        passed->insert(word.str);
        auto *nextChain = new WordChain();
        nextChain->append(*prevChain);
        nextChain->append(word);
        searchPathsFrom(word.getTailLetter() - 'a', nextChain, passed);
        passed->erase(word.str);
    }
}

WordChain SCComponent::getMostPathBetween(int from, int to) {
    if (sccMostPath[from][to] == nullptr) {
//        cout << "No path between " << (char)('a' + from) << " " << (char)('a' + to) << endl;
        return {};
    }
    return *sccMostPath[from][to];
}

WordChain SCComponent::getLongestPathBetween(int from, int to) {
    if (sccLongestPath[from][to] == nullptr) {
//        cout << "No path between " << (char)('a' + from) << " " << (char)('a' + to) << endl;
        return {};
    }
//    cout << "Path between " << (char)('a' + from) << " " << (char)('a' + to) << ": " << sccLongestPath[from][to]->toString() << endl;
    return *sccLongestPath[from][to];
}
